package ai.plantdata.dao.strategy.relation;

import ai.plantdata.dao.strategy.RelationHandle;
import ai.plantdata.dao.strategy.SeparateHandle;
import ai.plantdata.dao.util.JdbcUtils;
import ai.plantdata.graph.api.Node;
import ai.plantdata.graph.api.Property;
import ai.plantdata.graph.api.Relationship;
import ai.plantdata.graph.api.schema.ConceptDefinition;
import ai.plantdata.graph.api.schema.DataType;
import ai.plantdata.graph.api.schema.RelationDefinition;
import ai.plantdata.graph.api.schema.RelationNumericDefinition;
import ai.plantdata.graph.mongo.MongoGraphStore;
import ai.plantdata.util.SeparateStrategyUtils;
import ai.plantdata.vo.AssociationTable;
import ai.plantdata.vo.DataSourceConfig;
import ai.plantdata.vo.SeparateTable;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

/**
 * @Author: WangHui
 * @Date: 2021/7/19 16:53
 * @Description:
 */
@Component
public class RelationHandleImpl implements RelationHandle {

    @Override
    public List<ConceptDefinition> schemaHandle(AssociationTable associationTable, DataSourceConfig dataSourceConfig, Map<String, SeparateTable> map, MongoGraphStore store) {
        String tableName = associationTable.getTableName();
        String name = associationTable.getName();
        if (name == null) {
            name = tableName;
        }

        AssociationTable.Table from = associationTable.getFrom();
        String tableNameFrom = from.getTableName();
        SeparateTable fromSeparateTable = map.get(tableNameFrom);
        SeparateHandle select = SeparateStrategyUtils.select(fromSeparateTable.getStatus());
        List<ConceptDefinition> conceptDefinitionFrom = select.schemaHandle(fromSeparateTable, dataSourceConfig, store);

        AssociationTable.Table to = associationTable.getTo();
        String tableNameTo = to.getTableName();
        SeparateTable separateTable = map.get(tableNameTo);
        SeparateHandle selectTo = SeparateStrategyUtils.select(separateTable.getStatus());
        List<ConceptDefinition> conceptDefinitionsTo = selectTo.schemaHandle(separateTable, dataSourceConfig, store);

        List<String> attrField = associationTable.getAttrField();
        List<ConceptDefinition> conceptDefinitions = new ArrayList<>();
        Connection conn = JdbcUtils.getConnection(dataSourceConfig);
        for (ConceptDefinition conceptDefinition : conceptDefinitionFrom) {
            RelationDefinition relationDefinition = RelationDefinition.create(name);
            relationDefinition.setParent(conceptDefinition);
            relationDefinition.setRange(new HashSet<>(conceptDefinitionsTo));

            List<RelationNumericDefinition> relationNumericDefinitions = new ArrayList<>();
            if (!CollectionUtils.isEmpty(attrField)) {
                for (String attr : attrField) {
                    RelationNumericDefinition relationNumericDefinition = RelationNumericDefinition.create(attr);
                    int typeClass = getNumDef(conn, tableName, attr);
                    if (typeClass == -1) {
                        throw new RuntimeException("dataType错误");
                    }
                    relationNumericDefinition.setDataType(DataType.getByCode(typeClass));
                    relationNumericDefinitions.add(relationNumericDefinition);
                }
            }
            relationDefinition.setRelNumDefs(relationNumericDefinitions);
            conceptDefinition.setRelationDefinitions(Collections.singletonList(relationDefinition));
            conceptDefinitions.add(conceptDefinition);
            store.saveSchema(conceptDefinition);

        }
        return conceptDefinitions;
    }

    @Override
    public void entityHandle(AssociationTable associationTable, DataSourceConfig dataSourceConfig, MongoGraphStore store) {
        try {
            store.start();
            AssociationTable.Table from = associationTable.getFrom();
            AssociationTable.Table to = associationTable.getTo();
            Connection conn = JdbcUtils.getConnection(dataSourceConfig);
            String fromField = associationTable.getFromField();
            String toField = associationTable.getToField();
            String tableName = associationTable.getTableName();
            StringBuilder str = new StringBuilder();
            List<String> fieldName = associationTable.getAttrField();
            for (String s : fieldName) {
                str.append(" , ").append(s);
            }
            String sql = "select %s ,%s %s from %s";
            sql = String.format(sql, fromField, toField, str, tableName);
            PreparedStatement ps = conn.prepareStatement(sql);
            ResultSet rs = ps.executeQuery();
            List<Relationship> relationships = new ArrayList<>();
            while (rs.next()) {
                Map<String, String> associateFrom = getAssociate(conn, setAssociateDto(from), rs.getObject(1));
                if (associateFrom == null) {
                    throw new RuntimeException("关系实体1不存在");
                }
                Map<String, String> associateTo = getAssociate(conn, setAssociateDto(to), rs.getObject(2));
                if (associateTo == null) {
                    throw new RuntimeException("关系实体2不存在");
                }
                Node fromNode = Node.create(associateFrom.get("name"), associateFrom.get("meanTag"));
                Node toNode = Node.create(Node.create(associateTo.get("name"), associateTo.get("meanTag")));
                Relationship relationship = Relationship.create(fromNode, associationTable.getName(), toNode);
                List<Property> properties = new ArrayList<>();
                for (int i = 0; i < fieldName.size(); i++) {
                    Property property = Property.create(fieldName.get(i), rs.getObject(3 + i));
                    properties.add(property);
                }
                relationship.setProperties(properties);
                relationships.add(relationship);
                if (relationships.size() % 10_000 == 0) {
                    //保存关系
                    store.saveRelationshipWithProperty(relationships);
                    relationships.clear();
                }
                if (!relationships.isEmpty()) {
                    store.saveRelationshipWithProperty(relationships);
                    relationships.clear();
                }
            }
            JdbcUtils.close(ps, rs);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

}
